package com.actionsoft.demo.controller;

import com.actionsoft.bpms.bo.engine.BO;
import com.actionsoft.bpms.commons.formfile.model.delegate.FormFile;
import com.actionsoft.bpms.server.bind.annotation.Controller;
import com.actionsoft.bpms.server.bind.annotation.HandlerType;
import com.actionsoft.bpms.server.fs.DCContext;
import com.actionsoft.sdk.local.SDK;
import com.actionsoft.sdk.local.api.BOAPI;
import com.aliyun.dysmsapi20170525.models.SendSmsRequest;
import com.aliyun.dysmsapi20170525.models.SendSmsResponse;
import com.aliyun.teaopenapi.models.Config;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.json.JSONObject;
import redis.clients.jedis.Jedis;
import com.aliyun.dysmsapi20170525.Client;

import javax.ws.rs.*;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

@Controller(type = HandlerType.RESTFUL, apiName = "alumniApi", desc = "校友信息查询API")
@Path("/alumni")
public class AlumniInfoController {

    // ============ Redis 连接信息 ============
    private static final String REDIS_HOST = "localhost";
    private static final int REDIS_PORT = 6379;
    //获取 Jedis 实例
    private Jedis getJedis() {return new Jedis(REDIS_HOST, REDIS_PORT);}

    // 使用正确的API路径（全路径）
    private static final String USER_CREATE_API = "http://10.0.20.35:8088/api/org/v1/user";
    private static final String ACCESS_KEY = "aws";
    private static final String SECRET_KEY = "123456";
    private static final String DEFAULT_ROLE_ID = "acb05afd-b635-4f22-9b4c-c5d400c9b5b1";
    private static final String DEFAULT_DEPARTMENT_ID = "521cb7a3-e904-49f5-8204-b52a72b55034";

    // 微信小程序配置
    private static final String WECHAT_APP_ID = "wx8c6a587df8a16008";
    private static final String WECHAT_APP_SECRET = "9239382505ef10058f1e2b8d02f9733d";

    @Path("/loginWithIdCard")
    @POST
    @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
    @Produces(MediaType.APPLICATION_JSON)
    public Response loginWithIdCard(
            @FormParam("name") String name,
            @FormParam("idCard") String idCard,
            @FormParam("phone") String phone,
            @FormParam("code") String code) { // 新增code参数

        System.out.println("Received loginWithIdCard request: name=" + name + ", idCard=" + idCard + ", code=" + code);

        if (name == null || name.isEmpty() || idCard == null || idCard.isEmpty() || code == null || code.isEmpty()) {
            return badRequest("姓名、身份证号和code不能为空");
        }

        BOAPI boApi = SDK.getBOAPI();
        BO alumniInfo = null;
        String recordId = null; // 保存记录的主键ID

        try {
            // 提取身份证后6位作为密码
            String password = extractPasswordFromIdCard(idCard);
            System.out.println("Using password (last 6 digits): " + password);

            System.out.println("Querying BO_EU_XIAOYOUXINXI with name=" + name + ", idCard=" + idCard);

            // 修正查询语法 - 明确指定运算符
            List<BO> alumniList = boApi.query("BO_EU_XIAOYOUXINXI")
                    .addQuery("ALUMNI_NAME = ", name)  // 明确指定运算符
                    .addQuery("ID_CARD = " , idCard)    // 明确指定运算符
                    .list();

            if (alumniList == null || alumniList.isEmpty()) {
                System.out.println("No alumni found for name=" + name + ", idCard=" + idCard);
                return notFound("未找到匹配的校友信息");
            }

            alumniInfo = alumniList.get(0);
            System.out.println("Found alumni: " + alumniInfo);

            // 获取记录的主键ID
            recordId = alumniInfo.getString("ID");
            if (recordId == null || recordId.isEmpty()) {
                System.err.println("Missing record ID for alumni: " + alumniInfo);
                return internalServerError("校友信息缺少主键ID");
            }

            // 获取创建账户所需的字段
            String alumniId = alumniInfo.getString("ALUMNI_ID");
            String alumniName = alumniInfo.getString("ALUMNI_NAME");
            String authStatus = alumniInfo.getString("AUTH_STATUS");

            if (alumniId == null || alumniId.isEmpty() || alumniName == null || alumniName.isEmpty()) {
                System.err.println("Missing required fields: ALUMNI_ID=" + alumniId + ", ALUMNI_NAME=" + alumniName);
                return internalServerError("校友信息缺少必要的字段");
            }

            // 使用code获取token（openid）
            Map<String, String> sessionInfo = getWechatSession(code);
            String token = sessionInfo.get("openid");
            if (token == null || token.isEmpty()) {
                System.err.println("Failed to get token from code");
                return internalServerError("获取token失败");
            }

            // 将token更新到校友信息表的SESSION_DATA字段
            boolean updateTokenSuccess = updateSessionData(recordId, token);
            if (!updateTokenSuccess) {
                System.err.println("Failed to update token for alumniId=" + alumniId);
                return internalServerError("token更新失败");
            }

            // 检查认证状态
            if ("未注册".equals(authStatus)||"未认证".equals(authStatus)) {
                System.out.println("Creating account for alumniId=" + alumniId + ", alumniName=" + alumniName);
                // 传递密码参数
                boolean createSuccess = createUserAccount(alumniId, alumniName, password);

                if (createSuccess) {
                    System.out.println("Account created successfully for " + alumniName);

                    // 更新认证状态为"已注册" - 使用记录的主键ID
                    boolean updateStatusSuccess = updateAuthStatus(recordId, "已注册");
                    if (!updateStatusSuccess) {
                        System.err.println("Failed to update auth status for alumniId=" + alumniId);
                        return internalServerError("账户创建成功但状态更新失败");
                    }

                    // 重新查询校友信息以获取更新后的状态
                    alumniList = boApi.query("BO_EU_XIAOYOUXINXI")
                            .addQuery("ID = ", recordId) // 使用主键ID查询
                            .list();

                    if (alumniList != null && !alumniList.isEmpty()) {
                        alumniInfo = alumniList.get(0);
                        System.out.println("Updated alumni info after registration: " + alumniInfo);
                    }
                } else {
                    return internalServerError("账户创建失败");
                }
            } else {
                System.out.println("Account already registered for alumniId=" + alumniId);
            }

            // 返回完整的校友信息（移除身份证号）
            Map<String, Object> result = convertBoToMap(alumniInfo);
            result.remove("ID_CARD"); // 移除身份证号字段
            return Response.ok(result).build();

        } catch (Exception e) {
            System.err.println("Error in loginWithIdCard: " + e.getMessage());
            e.printStackTrace();
            return handleException(e);
        }
    }

    /**
     * 接口2：手机号登录
     */
    @Path("/loginWithMobile")
    @POST
    @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
    @Produces(MediaType.APPLICATION_JSON)
    public Response loginWithMobile(@FormParam("mobile") String mobile,
                                    @FormParam("code") String code) {
        System.out.println("Received loginWithMobile request: mobile=" + mobile);

        if (mobile == null || mobile.isEmpty()) {
            return badRequest("手机号不能为空");
        }

        BOAPI boApi = SDK.getBOAPI();

        try {
            System.out.println("Querying BO_EU_XIAOYOUXINXI with mobile=" + mobile);

            // 修正查询语法 - 明确指定运算符
            List<BO> alumniList = boApi.query("BO_EU_XIAOYOUXINXI")
                    .addQuery("PHONE = ", mobile)
                    .addQuery("AUTH_STATUS =","已注册")// 明确指定运算符
                    .list();
            String alumni_id =alumniList.get(0).getString("ALUMNI_ID");
            Map<String,Object> alumniexList = boApi.query("BO_EU_XIAOYOUTUOZHANXINXI")
                    .addQuery("ALUMNI_ID = ", alumni_id)  // 明确指定运算符
                    .detail().asMap();

            if (alumniList == null || alumniList.isEmpty()) {
                System.out.println("No alumni found for mobile=" + mobile);
                return notFound("未找到匹配的校友信息");
            }

            BO alumniInfo = alumniList.get(0);
            System.out.println("Found alumni: " + alumniInfo);

            // 返回校友信息
            Map<String, Object> result = convertBoToMap(alumniInfo);
            result.put("ALUMNI_COVER",buildFileUrl(alumniInfo.getId(),"ALUMNI_COVER") );
            result.putAll(alumniexList);
            return Response.ok(result).build();

        } catch (Exception e) {
            System.err.println("Error in loginWithMobile: " + e.getMessage());
            e.printStackTrace();
            return handleException(e);
        }
    }

    /**
     * 接口3：通过token登录（小程序登录）
     */
    @Path("/loginWithToken")
    @POST
    @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
    @Produces(MediaType.APPLICATION_JSON)
    public Response loginWithToken(@FormParam("token") String token) {
        System.out.println("Received loginWithToken request: token=" + token);

        if (token == null || token.isEmpty()) {
            return badRequest("token不能为空");
        }

        BOAPI boApi = SDK.getBOAPI();

        try {
            System.out.println("Querying BO_EU_XIAOYOUXINXI with token=" + token);

            // 根据token查询校友信息
            List<BO> alumniList = boApi.query("BO_EU_XIAOYOUXINXI")
                    .addQuery("SESSION_DATA = ", token)  // 使用SESSION_DATA字段查询
                    .list();

            if (alumniList == null || alumniList.isEmpty()) {
                System.out.println("No alumni found for token=" + token);
                return notFound("未找到匹配的校友信息");
            }

            BO alumniInfo = alumniList.get(0);
            System.out.println("Found alumni: " + alumniInfo);

            // 返回校友信息
            Map<String, Object> result = convertBoToMap(alumniInfo);
            result.remove("ID_CARD"); // 移除身份证号字段
            return Response.ok(result).build();

        } catch (Exception e) {
            System.err.println("Error in loginWithToken: " + e.getMessage());
            e.printStackTrace();
            return handleException(e);
        }
    }

    /**
     * 微信人脸核身：获取 verifyToken
     */
    @Path("/getVerifyInfo")
    @POST
    @Consumes(MediaType.APPLICATION_JSON)
    @Produces(MediaType.APPLICATION_JSON)
    public Response getVerifyInfo(Map<String, String> body) {
        String name     = body.get("name");
        String idCard   = body.get("idCard");
        if (name == null || idCard == null) {
            return badRequest("姓名或身份证号缺失");
        }
        try {
            // 1. 获取 access_token
            String tokenUrl = "https://api.weixin.qq.com/cgi-bin/token"
                    + "?grant_type=client_credential"
                    + "&appid="     + WECHAT_APP_ID
                    + "&secret="    + WECHAT_APP_SECRET;
            Map<?,?> tokenMap = new ObjectMapper().readValue(
                    new URL(tokenUrl).openStream(), Map.class);
            String accessToken = (String) tokenMap.get("access_token");
            if (accessToken == null) {
                return Response.status(502).entity("获取 access_token 失败").build();
            }

            // 2. 上传姓名+身份证换取 user_id_key
            String postUrl = "https://api.weixin.qq.com/cityservice/face/identify/getuseridkey"
                    + "?access_token=" + accessToken;
            String jsonBody = new ObjectMapper().writeValueAsString(
                    Map.of("name", name, "id_card_number", idCard));
            HttpURLConnection conn = (HttpURLConnection) new URL(postUrl).openConnection();
            conn.setRequestMethod("POST");
            conn.setRequestProperty("Content-Type", "application/json");
            conn.setDoOutput(true);
            try (var os = conn.getOutputStream()) {
                os.write(jsonBody.getBytes(StandardCharsets.UTF_8));
            }
            Map<?,?> resp = new ObjectMapper().readValue(conn.getInputStream(), Map.class);
            if (!resp.containsKey("user_id_key")) {
                return Response.status(502).entity("微信返回异常").build();
            }

            // 3. 将 user_id_key 作为 verifyToken 返回给前端
            return Response.ok(Map.of("verifyToken", resp.get("user_id_key"))).build();
        } catch (Exception e) {
            e.printStackTrace();
            return handleException(e);
        }
    }

    /**
     * 接口3：人脸识别注册/登录（复用手机短信流程）
     */
    @Path("/loginWithFace")
    @POST
    @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
    @Produces(MediaType.APPLICATION_JSON)
    public Response loginWithFace(@FormParam("verifyResult") String verifyResult) {
        if (verifyResult == null || verifyResult.isEmpty()) {
            return badRequest("verifyResult 不能为空");
        }

        try {
            // 1. 拉取 access_token
            String tokenUrl = "https://api.weixin.qq.com/cgi-bin/token"
                    + "?grant_type=client_credential"
                    + "&appid="  + WECHAT_APP_ID
                    + "&secret=" + WECHAT_APP_SECRET;
            Map<?,?> tokenMap = new ObjectMapper().readValue(
                    new URL(tokenUrl).openStream(), Map.class);
            String accessToken = (String) tokenMap.get("access_token");
            if (accessToken == null) {
                return Response.status(502).entity("获取 access_token 失败").build();
            }

            // 2. 二次核验
            String checkUrl = "https://api.weixin.qq.com/cityservice/face/identify/getinfo"
                    + "?access_token=" + accessToken;
            String reqBody  = new ObjectMapper()
                    .writeValueAsString(Map.of("verify_result", verifyResult));
            HttpURLConnection conn = (HttpURLConnection) new URL(checkUrl).openConnection();
            conn.setRequestMethod("POST");
            conn.setRequestProperty("Content-Type", "application/json");
            conn.setDoOutput(true);
            try (var os = conn.getOutputStream()) {
                os.write(reqBody.getBytes(StandardCharsets.UTF_8));
            }
            Map<?,?> wxResp = new ObjectMapper().readValue(conn.getInputStream(), Map.class);

            if (!"0".equals(String.valueOf(wxResp.get("errcode")))
                    || !"0".equals(String.valueOf(wxResp.get("identify_ret")))) {
                return Response.status(400).entity(Map.of("msg", "人脸核验未通过")).build();
            }

            // 3. 取出姓名、身份证
            String nameMd5 = (String) wxResp.get("name_utf8_md5");
            String idMd5   = (String) wxResp.get("id_card_number_md5");
            // 简单做法：直接用 MD5 反查库
            BOAPI boApi = SDK.getBOAPI();
            List<BO> list = boApi.query("BO_EU_XIAOYOUXINXI")
                    .addQuery("NAME_MD5 = ", nameMd5.toUpperCase())
                    .addQuery("IDCARD_MD5 = ", idMd5.toUpperCase())
                    .list();
            if (list == null || list.isEmpty()) {
                return notFound("未找到匹配的校友信息");
            }

            // 4. 返回校友信息（与手机登录一致）
            Map<String, Object> result = convertBoToMap(list.get(0));
            return Response.ok(result).build();

        } catch (Exception e) {
            e.printStackTrace();
            return handleException(e);
        }
    }
/*************************短信验证代码****************************/

    /**
     * 单文件 SMS 登录验证码实现
     * 访问：
     * POST /sms/sendCode?phone=13812345678
     * POST /sms/verifyCode?phone=13812345678&code=123456
     */

        /* ============ 阿里云账号配置 ============ */
        private static final String ACCESS_KEY_ID = "LTAI5t6vSwUPyHPttfD9R5H7";
        private static final String ACCESS_KEY_SECRET = "Kk06ZagGSWMgAxqpcYLp9UeLZzZDKl";
        private static final String SIGN_NAME = "北京理工大学";
        private static final String TEMPLATE_CODE = "SMS_492555687";

        /* ============ 验证码有效期(秒) ============ */
        private static final int CODE_EXPIRE_SEC = 300;

        /* ---------- 工具：本地缓存 ---------- */
        private static class LocalCache {
            private static final Map<String, CacheValue> STORE = new ConcurrentHashMap<>();
            private static final ScheduledExecutorService CLEANER =
                    Executors.newSingleThreadScheduledExecutor(r -> new Thread(r, "LocalCache-Cleaner"));

            public static void put(String key, Object value, int ttlSeconds) {
                long expireAt = System.currentTimeMillis() + ttlSeconds * 1000L;
                STORE.put(key, new CacheValue(value, expireAt));
                CLEANER.schedule(() -> STORE.remove(key), ttlSeconds, TimeUnit.SECONDS);
            }

            public static Object get(String key) {
                CacheValue cv = STORE.get(key);
                if (cv == null || cv.expireAt < System.currentTimeMillis()) {
                    STORE.remove(key);
                    return null;
                }
                return cv.value;
            }

            public static void remove(String key) {
                STORE.remove(key);
            }

            private static class CacheValue {
                final Object value;
                final long expireAt;

                CacheValue(Object value, long expireAt) {
                    this.value = value;
                    this.expireAt = expireAt;
                }
            }
        }

        /* ---------- 工具：阿里云 Client ---------- */
        private Client createClient() throws Exception {
            Config cfg = new Config()
                    .setAccessKeyId(ACCESS_KEY_ID)
                    .setAccessKeySecret(ACCESS_KEY_SECRET);
            cfg.endpoint = "dysmsapi.aliyuncs.com";
            return new Client(cfg);
        }

        /* ---------- 工具：随机数字 ---------- */
        private String randomNumeric(int len) {
            StringBuilder sb = new StringBuilder(len);
            for (int i = 0; i < len; i++) sb.append((int) (Math.random() * 10));
            return sb.toString();
        }

        /* ---------- 发送验证码 ---------- */
        @Path("/sms/sendCode")
        @Consumes(MediaType.APPLICATION_JSON)
        @Produces(MediaType.APPLICATION_JSON)
        @POST
        public Map<String, Object> sendCode(@QueryParam("phone") String phone) {
            Map<String, Object> res = new HashMap<>();
            if (phone == null || phone.trim().isEmpty()) {
                res.put("success", false);
                res.put("error", "手机号不能为空");
                return res;
            }
            String code = randomNumeric(6);
            System.out.println("隨機生成的傳輸码"+code);
            LocalCache.put("SMS_CODE_" + phone, code, CODE_EXPIRE_SEC);
            try {
                System.out.println("111111");
                Client client = createClient();
                SendSmsRequest req = new SendSmsRequest()
                        .setPhoneNumbers(phone)
                        .setSignName(SIGN_NAME)
                        .setTemplateCode(TEMPLATE_CODE)
                        .setTemplateParam("{\"code\":\"" + code + "\"}");
                SendSmsResponse resp = client.sendSms(req);
                System.out.println("222222");
                if (!"OK".equals(resp.getBody().getCode())) {
                    throw new RuntimeException(resp.getBody().getMessage());
                }
                res.put("success", true);
                res.put("phone", phone);
            } catch (Exception e) {
                res.put("success", false);
                res.put("error", e.getMessage());
            }
            return res;
        }

        /* ---------- 校验验证码 ---------- */
        @POST
        @Path("/api/verifyCode")
        @Consumes(MediaType.APPLICATION_JSON)
        @Produces(MediaType.APPLICATION_JSON)
        public Map<String, Object> verifyCode(@QueryParam("phone") String phone,
                                              @QueryParam("code") String code) {
            Map<String, Object> res = new HashMap<>();
            if (phone == null || code == null) {
                res.put("success", false);
                res.put("error", "参数缺失");
                return res;
            }
            String key = "SMS_CODE_" + phone;
            String cached = (String) LocalCache.get(key);
            if (cached == null) {
                res.put("success", false);
                res.put("error", "验证码已过期");
                return res;
            }
            if (!cached.equals(code.trim())) {
                res.put("success", false);
                res.put("error", "验证码错误");
                return res;
            }
            LocalCache.remove(key);
            res.put("success", true);
            /* 这里可以继续写登录逻辑，如生成 JWT、写 session 等 */
            return res;
        }

    /* ---------- 交换信息短信 RESTful ---------- */
    private static final String TEMPLATE_EXCHANGE = "SMS_493290481";

    @POST
    @Path("/api/sendExchange")
    @Consumes(MediaType.APPLICATION_JSON)
    @Produces(MediaType.APPLICATION_JSON)
    public Map<String, Object> sendExchange(@QueryParam("EXCHANGE_ALUMNI_ID") String exchangeId,
                                            @QueryParam("BEEXCHANGE_ALUMNI_ID") String beExchangeId) {
        Map<String, Object> res = new HashMap<>();

        try {
            // 被交换人
            BO be = SDK.getBOAPI()
                    .query("BO_EU_XIAOYOUXINXI")
                    .addQuery("ALUMNI_ID =", beExchangeId)
                    .addQuery("AUTH_STATUS =", "已注册")
                    .list().get(0);

            String phone   = (String) be.get("CONTACT_PHONE");
            String name    = (String) be.get("ALUMNI_NAME");

            // 交换人
            BO me = SDK.getBOAPI()
                    .query("BO_EU_XIAOYOUXINXI")
                    .addQuery("ALUMNI_ID =", exchangeId)
                    .list().get(0);

            String year    = (String) me.get("COLLEGE_IN");
            String xyName  = (String) me.get("COLLEGE_NAME");
            String name2   = (String) me.get("ALUMNI_NAME");
            System.out.println("phone"+phone+name+year+xyName+name2);
            // 发送短信
            sendExchangeSms(phone, name, year, xyName, name2);
            res.put("success", true);
            res.put("phone", phone);
        } catch (Exception e) {
            res.put("success", false);
            res.put("error", e.getMessage());
        }
        return res;
    }

    @GET
    @Path("/sms/template/{code}")
    @Produces(MediaType.APPLICATION_JSON)
    public Response checkTemplate(@PathParam("code") String code) {
        try {
            return Response.ok(validateTemplate(code)).build();
        } catch (Exception e) {
            return Response.serverError().entity(Map.of("error", e.getMessage())).build();
        }
    }

    /* ---------- 发送交换短信 ---------- */
    private void sendExchangeSms(String phone, String name,
                                 String year, String xyName, String name2) throws Exception {
        Client client = createClient();
        String param = new ObjectMapper()
                .writeValueAsString(Map.of(
                        "name", name,
                        "year", year,
                        //"xy_name", xyName,
                        "name2", name2
                ));

        SendSmsRequest req = new SendSmsRequest()
                .setPhoneNumbers(phone)
                .setSignName(SIGN_NAME)
                .setTemplateCode(TEMPLATE_EXCHANGE)
                .setTemplateParam(param);

        SendSmsResponse resp = client.sendSms(req);
        if (!"OK".equals(resp.body.code)) {
            throw new RuntimeException(resp.body.message);
        }
    }

    /**
     * 通过模板 CODE 查询模板详情（内容、变量、审核状态）
     * 返回 Map：content / variables / status
     */
    public Map<String, Object> validateTemplate(String templateCode) throws Exception {
        com.aliyun.dysmsapi20170525.Client client = createClient(); // 复用已有方法
        com.aliyun.dysmsapi20170525.models.GetSmsTemplateRequest req =
                new com.aliyun.dysmsapi20170525.models.GetSmsTemplateRequest()
                        .setTemplateCode(templateCode);

        var resp = client.getSmsTemplate(req);
        Map<String, Object> info = new HashMap<>();
        info.put("content", resp.body.templateContent);   // 模板原文
        info.put("status", resp.body.templateStatus);     // 0-审核中 1-已通过 2-未通过
        info.put("reason", resp.body.remark);             // 审核失败原因
        info.put("variables", parseTemplateVars(resp.body.templateContent));
        return info;
    }

    /** 从模板文本提取所有 ${xxx} 变量名 */
    private List<String> parseTemplateVars(String tpl) {
        java.util.regex.Pattern p = java.util.regex.Pattern.compile("\\$\\{([^}]+)\\}");
        java.util.regex.Matcher m = p.matcher(tpl);
        List<String> vars = new ArrayList<>();
        while (m.find()) vars.add(m.group(1));
        return vars;
    }

    private static final String ALI_TEMPLATE   = "SMS_490530100";
    private static final String UPDATE_URL     =
            "http://10.0.12.100:7080/api/v2/info/updateInfo";
    /* ====== 主接口 ====== */
    @POST
    @Path("/api/sendIn")
    @Consumes(MediaType.APPLICATION_JSON)
    @Produces(MediaType.APPLICATION_JSON)
    public Map<String, Object> sendInAndUpdate(Map<String, Object> body) {

        Map<String, Object> res = new HashMap<>();
        String phone    = (String) body.get("phone");
        String id       = (String) body.get("id");
        int    type     = (int)    body.get("type");
        String start    = (String) body.get("timeStart");
        String end      = (String) body.get("timeEnd");
        String dir      = (String) body.get("direction");
        int    allow    = (int)    body.get("allow");
        String remark   = (String) body.get("remark");
        String unPassReason = (String) body.get("unPassReason");

        try {
            /* 1. 更新进校权限（JSON） */
            Map<String, Object> update = updateAccess(id, type, start, end, dir, allow, remark, unPassReason);
            if (!"200".equals(update.get("code") + "")) {
                res.put("success", false);
                res.put("error", "更新失败：" + update.get("msg"));
                return res;
            }

            /* 2. 发送入校短信 */
            sendInSms(phone, start, end);
            res.put("success", true);
            res.put("phone", phone);
        } catch (Exception e) {
            res.put("success", false);
            res.put("error", e.getMessage());
        }
        return res;
    }

    /* ---------- 1. 更新进校权限（POST JSON） ---------- */
    private Map<String, Object> updateAccess(String id, int type,
                                             String start, String end,
                                             String dir, int allow, String remark,
                                             String unPassReason) throws Exception {

        Map<String, Object> payload = new HashMap<>();
        payload.put("id", id);
        payload.put("type", type);
        payload.put("timeStart", start);
        payload.put("timeEnd", end);
        payload.put("direction", dir);
        payload.put("allow", allow);
        payload.put("remark", remark);
        payload.put("unPassReason", unPassReason);
        payload.put("sign", md5(id + type + start + end + "bitzh2021")); // 无空格

        String json = new com.fasterxml.jackson.databind.ObjectMapper().writeValueAsString(payload);

        HttpURLConnection conn = (HttpURLConnection) new URL(UPDATE_URL).openConnection();
        conn.setRequestMethod("POST");
        conn.setRequestProperty("Content-Type", "application/json; charset=utf-8");
        conn.setDoOutput(true);

        try (OutputStream os = conn.getOutputStream()) {
            os.write(json.getBytes(StandardCharsets.UTF_8));
        }

        if (conn.getResponseCode() != 200) {
            throw new RuntimeException("更新接口返回 " + conn.getResponseCode());
        }

        try (BufferedReader br = new BufferedReader(
                new InputStreamReader(conn.getInputStream(), StandardCharsets.UTF_8))) {
            return new com.fasterxml.jackson.databind.ObjectMapper()
                    .readValue(br, Map.class);
        }
    }



    /* ===== 亲友进校常量 ===== */
    private static final String MAINTAIN_URL ="http://10.0.12.100:7080/api/v2/info/maintainInfo";

    /* 亲友进校接口 */
    @POST
    @Path("/api/sendRelative")
    @Consumes(MediaType.APPLICATION_JSON)
    @Produces(MediaType.APPLICATION_JSON)
    public Map<String, Object> sendRelative(Map<String, Object> body) {

        Map<String, Object> res = new HashMap<>();

        try {
            /* 1. 亲友信息维护 */
            Map<String, Object> resp = maintainRelative(body);
            if (!"200".equals(resp.get("code") + "")) {
                res.put("success", false);
                res.put("error", resp.get("msg"));
                return res;
            }

            /* 2. 发送入校短信 */
            sendInSms(
                    (String) body.get("phone"),
                    (String) body.get("timeStart"),
                    (String) body.get("timeEnd")
            );
            res.put("success", true);
            res.put("phone", body.get("phone"));
        } catch (Exception e) {
            res.put("success", false);
            res.put("error", e.getMessage());
        }
        return res;
    }

    /* 1. 亲友信息维护（无工具类） */
    private Map<String, Object> maintainRelative(Map<String, Object> body) throws Exception {

        Map<String, Object> payload = new HashMap<>();
        payload.put("id",      body.get("id"));         // 学号/工号
        payload.put("idcard",  body.get("idcard"));     // 身份证号
        payload.put("name",    body.get("name"));
        payload.put("peopleType", body.get("peopleType"));
        payload.put("sex",     body.get("sex"));
        payload.put("type",    ((Number) body.get("type")).intValue());
        payload.put("timeStart", body.get("timeStart"));
        payload.put("timeEnd",   body.get("timeEnd"));
        payload.put("direction", body.get("direction"));
        payload.put("allow",     ((Number) body.get("allow")).intValue());
        payload.put("peopleType2",body.get("peopleType2"));
        payload.put("remark",    body.getOrDefault("remark", ""));
        payload.put("unPassReason", body.get("unPassReason"));

        /* 1-1 计算 MD5：id+idcard+name+bitzh2021 */
        String signPlain = payload.get("id") + "" +
                payload.get("idcard") + "" +
                payload.get("name") + "bitzh2021";
        MessageDigest md = MessageDigest.getInstance("MD5");
        byte[] bytes = md.digest(signPlain.getBytes(StandardCharsets.UTF_8));
        StringBuilder sb = new StringBuilder();
        for (byte b : bytes) sb.append(String.format("%02x", b));
        payload.put("sign", sb.toString());

        /* 1-2 转 JSON */
        String json = new com.fasterxml.jackson.databind.ObjectMapper()
                .writeValueAsString(payload);

        /* 1-3 发送 POST */
        HttpURLConnection conn = (HttpURLConnection)
                new URL(MAINTAIN_URL).openConnection();
        conn.setRequestMethod("POST");
        conn.setRequestProperty("Content-Type", "application/json; charset=utf-8");
        conn.setDoOutput(true);

        try (OutputStream os = conn.getOutputStream()) {
            os.write(json.getBytes(StandardCharsets.UTF_8));
        }

        try (BufferedReader br = new BufferedReader(
                new InputStreamReader(conn.getInputStream(), StandardCharsets.UTF_8))) {
            return new com.fasterxml.jackson.databind.ObjectMapper()
                    .readValue(br, Map.class);
        }
    }

    /* ---------- 2. 发送入校短信 ---------- */
    private void sendInSms(String phone, String start, String end) throws Exception {
        com.aliyun.dysmsapi20170525.Client client =
                new com.aliyun.dysmsapi20170525.Client(
                        new com.aliyun.teaopenapi.models.Config()
                                .setAccessKeyId(ACCESS_KEY_ID)
                                .setAccessKeySecret(ACCESS_KEY_SECRET)
                                .setEndpoint("dysmsapi.aliyuncs.com"));

        String paramJson = "{\"JXSJ\":\"" + start + "\",\"CXSJ\":\"" + end + "\"}";
        com.aliyun.dysmsapi20170525.models.SendSmsRequest req =
                new com.aliyun.dysmsapi20170525.models.SendSmsRequest()
                        .setPhoneNumbers(phone)
                        .setSignName(SIGN_NAME)
                        .setTemplateCode(ALI_TEMPLATE)
                        .setTemplateParam(paramJson);

        com.aliyun.dysmsapi20170525.models.SendSmsResponse resp = client.sendSms(req);
        if (!"OK".equals(resp.body.code)) {
            throw new RuntimeException(resp.body.message);
        }
    }

    /* ---------- 工具：MD5 ---------- */
    private static String md5(String data) throws Exception {
        MessageDigest md = MessageDigest.getInstance("MD5");
        byte[] b = md.digest(data.getBytes(StandardCharsets.UTF_8));
        StringBuilder sb = new StringBuilder();
        for (byte x : b) sb.append(String.format("%02x", x));
        return sb.toString();
    }

    private static final String TEMPLATE_BIRTHDAY = "SMS_492445748";

    /* ====== 生日祝福短信接口 ====== */
    @POST
    @Path("/api/sendBirthday")
    @Consumes(MediaType.APPLICATION_JSON)
    @Produces(MediaType.APPLICATION_JSON)
    public Map<String, Object> sendBirthday(
            @FormParam("phone") String phone,
            @FormParam("name")  String name) {

        Map<String, Object> res = new HashMap<>();
        if (phone == null || phone.trim().isEmpty()) {
            res.put("success", false);
            res.put("error", "手机号不能为空");
            return res;
        }

        try {
            /* 1. 创建 Client */
            com.aliyun.teaopenapi.models.Config cfg =
                    new com.aliyun.teaopenapi.models.Config()
                            .setAccessKeyId(ACCESS_KEY_ID)
                            .setAccessKeySecret(ACCESS_KEY_SECRET)
                            .setEndpoint("dysmsapi.aliyuncs.com");
            com.aliyun.dysmsapi20170525.Client client =
                    new com.aliyun.dysmsapi20170525.Client(cfg);

            /* 2. 构造参数 */
            Map<String, String> param = new HashMap<>();
            param.put("name", name);

            /* 3. 发送短信 */
            com.aliyun.dysmsapi20170525.models.SendSmsRequest req =
                    new com.aliyun.dysmsapi20170525.models.SendSmsRequest()
                            .setPhoneNumbers(phone)
                            .setSignName(SIGN_NAME)
                            .setTemplateCode(TEMPLATE_BIRTHDAY)
                            .setTemplateParam("{\"name\":\"" + name + "\"}");

            com.aliyun.dysmsapi20170525.models.SendSmsResponse resp = client.sendSms(req);
            if (!"OK".equals(resp.body.code)) {
                res.put("success", false);
                res.put("error", resp.body.message);
            } else {
                res.put("success", true);
                res.put("phone", phone);
            }
        } catch (Exception e) {
            res.put("success", false);
            res.put("error", e.getMessage());
        }
        return res;
    }

    /**
     * 从身份证号提取后6位作为密码
     */
    private String extractPasswordFromIdCard(String idCard) {
        if (idCard == null || idCard.length() < 6) {
            return "123456"; // 默认密码
        }
        return idCard.substring(idCard.length() - 6);
    }

    /**
     * 创建用户账户 - 根据参数说明图片修改
     */
    private boolean createUserAccount(String uid, String userName, String password) {
        try {
            // 构造包含所有参数的URL查询字符串
            String queryString = String.format(
                    "departmentId=%s&uid=%s&userName=%s&roleId=%s&userNo=%s&password=%s&isManager=false", // 使用图片中的参数名 isManager
                    urlEncode(DEFAULT_DEPARTMENT_ID),
                    urlEncode(uid),
                    urlEncode(userName),
                    urlEncode(DEFAULT_ROLE_ID),
                    urlEncode(generateUserNo()),
                    urlEncode(password)
            );

            // 拼接完整URL
            String fullUrl = USER_CREATE_API + "?" + queryString;
            System.out.println("Creating account at: " + fullUrl);

            URL url = new URL(fullUrl);
            HttpURLConnection connection = (HttpURLConnection) url.openConnection();

            // 配置请求
            connection.setRequestMethod("POST");

            // 使用标准Basic认证
            String auth = ACCESS_KEY + ":" + SECRET_KEY;
            String encodedAuth = java.util.Base64.getEncoder().encodeToString(auth.getBytes());
            connection.setRequestProperty("Authorization", "Basic " + encodedAuth);
            connection.setDoOutput(true);

            // 添加必要的请求头
            connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");

            // 发送请求（空请求体）
            try (OutputStream os = connection.getOutputStream()) {
                // 查询字符串已包含在URL中，请求体保持为空
                os.write(new byte[0]);
            }

            // 处理响应
            int responseCode = connection.getResponseCode();
            System.out.println("Account creation response: " + responseCode);

            // 读取响应体
            String responseBody = readResponse(connection.getInputStream());
            System.out.println("Account creation response body: " + responseBody);

            // 如果响应码为200，认为创建成功
            return responseCode == HttpURLConnection.HTTP_OK;

        } catch (Exception e) {
            System.err.println("Error creating account: " + e.getMessage());
            e.printStackTrace();
            return false;
        }
    }

    /**
     * URL编码辅助方法
     */
    private String urlEncode(String value) {
        try {
            return java.net.URLEncoder.encode(value, StandardCharsets.UTF_8.name());
        } catch (Exception e) {
            System.err.println("URL encode error: " + e.getMessage());
            return value; // 失败时返回原始值
        }
    }

    /**
     * 更新认证状态 - 使用记录的主键ID
     */
    private boolean updateAuthStatus(String recordId, String newStatus) {
        BOAPI boApi = SDK.getBOAPI();

        try {
            BO updateBo = new BO();
            updateBo.set("ID", recordId); // 关键：使用记录的主键ID
            updateBo.set("AUTH_STATUS", newStatus); // 确保使用"已注册"而不是"01"

            int result = boApi.update("BO_EU_XIAOYOUXINXI", updateBo);
            System.out.println("Update auth status result for recordId=" + recordId +
                    " to " + newStatus + ": " + result);
            return result > 0;
        } catch (Exception e) {
            System.err.println("Error updating auth status: " + e.getMessage());
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 更新token到校友信息表的SESSION_DATA字段
     */
    private boolean updateSessionData(String recordId, String token) {
        BOAPI boApi = SDK.getBOAPI();

        try {
            BO updateBo = new BO();
            updateBo.set("ID", recordId); // 关键：使用记录的主键ID
            updateBo.set("SESSION_DATA", token); // 设置SESSION_DATA字段

            int result = boApi.update("BO_EU_XIAOYOUXINXI", updateBo);
            System.out.println("Update token result for recordId=" + recordId + ": " + result);
            return result > 0;
        } catch (Exception e) {
            System.err.println("Error updating token: " + e.getMessage());
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 将BO对象转换为Map - 包含所有字段
     */
    private Map<String, Object> convertBoToMap(BO bo) {
        Map<String, Object> result = new HashMap<>();
        // 列出所有可能的字段
        result.put("ID", bo.getString("ID"));
        result.put("ALUMNI_ID", bo.getString("ALUMNI_ID"));
        result.put("ALUMNI_NAME", bo.getString("ALUMNI_NAME"));
        result.put("GENDER", bo.getString("GENDER"));
        result.put("BIRTH_DATE", bo.getString("BIRTH_DATE"));
        result.put("PHONE", bo.getString("PHONE"));
        result.put("EMAIL", bo.getString("EMAIL"));
        result.put("ID_CARD", bo.getString("ID_CARD")); // 在loginWithIdCard方法中会移除
        result.put("AUTH_STATUS", bo.getString("AUTH_STATUS"));
        result.put("COLLEGE_EXPERIENCE", bo.getString("COLLEGE_EXPERIENCE"));
        result.put("COLLEGE_IN", bo.getString("COLLEGE_IN"));
        result.put("COLLEGE_OUT", bo.getString("COLLEGE_OUT"));
        result.put("COLLEGE_NAME", bo.getString("COLLEGE_NAME"));
        result.put("COLLEGE_ID", bo.getString("COLLEGE_ID"));
        result.put("MAJOR", bo.getString("MAJOR"));
        result.put("DEGREE", bo.getString("DEGREE"));
        result.put("CREATE_TIME", bo.getString("CREATE_TIME"));
        result.put("UPDATE_TIME", bo.getString("UPDATE_TIME"));
        result.put("CREATEDATE", bo.getString("CREATEDATE"));
        result.put("UPDATEDATE", bo.getString("UPDATEDATE"));
        result.put("INTEGRAL", bo.getString("INTEGRAL"));
        result.put("HIDE", bo.getString("HIDE"));
        result.put("SESSION_DATA", bo.getString("SESSION_DATA")); // 存储token的字段
        result.put("ALUMNI_COVER", bo.getString("ALUMNI_COVER"));
        result.put("ISEND", bo.getString("ISEND"));
        result.put("BINDID", bo.getString("BINDID"));
        result.put("ORGID", bo.getString("ORGID"));
        result.put("PROCESSDEFID", bo.getString("PROCESSDEFID"));
        result.put("CREATEUSER", bo.getString("CREATEUSER"));
        result.put("UPDATEUSER", bo.getString("UPDATEUSER"));
        result.put("CONTACT_PHONE",bo.getString("CONTACT_PHONE"));
        return result;
    }

    /**
     * 从微信小程序code获取session信息（openid等）
     */
    private Map<String, String> getWechatSession(String code) throws IOException {
        String url = "https://api.weixin.qq.com/sns/jscode2session?appid=" + WECHAT_APP_ID
                + "&secret=" + WECHAT_APP_SECRET
                + "&js_code=" + code
                + "&grant_type=authorization_code";
        URL wechatUrl = new URL(url);
        HttpURLConnection conn = (HttpURLConnection) wechatUrl.openConnection();
        conn.setRequestMethod("GET");
        conn.connect();
        InputStream is = conn.getInputStream();
        BufferedReader reader = new BufferedReader(new InputStreamReader(is, StandardCharsets.UTF_8));
        StringBuilder response = new StringBuilder();
        String line;
        while ((line = reader.readLine()) != null) {
            response.append(line);
        }
        reader.close();
        is.close();
        System.out.println("微信API返回: " + response.toString());

        Map<String, String> result = new HashMap<>();
        if (response.length() == 0) {
            System.err.println("微信API返回为空");
            return result;
        }

        try {
            JSONObject json = new JSONObject(response.toString());
            String openid = json.optString("openid");
            String sessionKey = json.optString("session_key");
            result.put("openid", openid);
            result.put("session_key", sessionKey);
        } catch (Exception e) {
            System.err.println("解析微信API返回异常: " + e.getMessage());
        }
        return result;
    }

    // 以下辅助方法保持不变...
    private String toJsonString(Map<String, Object> map) {
        // 保留此方法但当前未使用，可根据需要启用
        StringBuilder json = new StringBuilder("{");
        boolean first = true;
        for (Map.Entry<String, Object> entry : map.entrySet()) {
            if (!first) json.append(",");
            json.append("\"").append(entry.getKey()).append("\":");
            Object value = entry.getValue();
            if (value instanceof String) {
                json.append("\"").append(escapeJsonString((String) value)).append("\"");
            } else {
                json.append(value);
            }
            first = false;
        }
        json.append("}");
        return json.toString();
    }

    private String escapeJsonString(String input) {
        return input.replace("\"", "\\\"")
                .replace("\n", "\\n")
                .replace("\r", "\\r")
                .replace("\t", "\\t")
                .replace("\b", "\\b")
                .replace("\f", "\\f");
    }

    private String readResponse(InputStream inputStream) throws Exception {
        if (inputStream == null) return "";

        StringBuilder response = new StringBuilder();
        try (BufferedReader br = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8))) {
            String responseLine;
            while ((responseLine = br.readLine()) != null) {
                response.append(responseLine);
            }
        }
        return response.toString();
    }

    private String generateUserNo() {
        return UUID.randomUUID().toString().replaceAll("-", "").substring(0, 12);
    }

    private Response handleException(Exception e) {
        return internalServerError("系统错误: " + e.getMessage());
    }

    private Response badRequest(String message) {
        return Response.status(Response.Status.BAD_REQUEST)
                .entity("{\"error\":\"" + message + "\"}")
                .build();
    }

    private Response notFound(String message) {
        return Response.status(Response.Status.NOT_FOUND)
                .entity("{\"error\":\"" + message + "\"}")
                .build();
    }

    private Response internalServerError(String message) {
        return Response.serverError()
                .entity("{\"error\":\"" + message + "\"}")
                .build();
    }

    /*String uid, String pwd*/
    private String createClientSession() throws IOException {
        // 假设 SDK 返回的是整段 JSON 字符串
        String json = SDK.getPortalAPI().createClientSession("admin", "123"); // 固定账号返回sid
        ObjectMapper mapper = new ObjectMapper();
        // 只抓 sid
        return mapper.readTree(json).path("data").path("sid").asText();
    }
    //获取图片
    private String buildFileUrl(String boid, String field) throws IOException {

        String sid = createClientSession();
        List<FormFile> files = SDK.getBOAPI().getFiles(boid, field);
        if (files == null || files.isEmpty()) {
            return null;
        }
        DCContext context = SDK.getBOAPI().getFileDCContext(files.get(0));
        String url = context.getDownloadURL();      // 形如 "./df?sid=xxxxx..."
        url = url.replaceFirst("\\./df\\?sid=[^&]*", "/r/df?sid=" + sid); // 替换 sid
        String baseUrl = "https://xysq.bitzh.edu.cn";
        return baseUrl + url;
    }

}